Cryptography in Microsoft.NET Part I: Encryption

For any Distributed Framework or Infrastructure to be successful today it has to have an extensive support for developing secured solutions. Microsoft .NET is developed from bottom up with security in mind. It has an eclectic security infrastructure.

Security is a broad topic and it can be broadly split into 

  1. Authentication 
  2. Authorization 
  3. Privacy or Confidentiality
  4. Data Integrity
  5. Non-repudiation

While authentication is about proving one principals identity to another, authorization is about controlling access to secured resources based on the identity. Privacy deals with prevention of eaves dropping of messages sent across the wire. Data Integrity ensures that the message is not tampered on transit. Non-repudiation ensures that the author of the message/data cannot disavow responsibility.

Microsoft .NET has pre-built solutions to all of these in each application domain, viz., ASP. NET, Web Services, Serviced Component etc. It enables building secured application by simple configuration as in ASP.NET to full fledged programmable security as in code access security and Cryptography.

Cryptography

Cryptography is the art and science of keeping messages secure.

When a message is transferred from one place to another, it contents are readily available to an eavesdropper. A simple network-monitoring tool can expose the entire message sent from one computer to another in a graphical way. For an N-Tier or distributed application to be secure, all messages sent on the network should be scrambled in a way that it is computationally impossible for any one to read it.

In cryptography world the message that needs to be secured is called plaintext or cleartext. The scrambled form of the message is called ciphertext. The process of converting a plaintext to ciphertext is called encryption. The process of reconverting the ciphertext into plaintext is called decryption. Cryptography algorithms (ciphers) are mathematical functions used for encryption and decryptions.

For cryptography to be used in practical solutions algorithms used for encryption and decryption should be made public. This is possible by using a byte stream called Key. For the algorithm to encipher a plaintext to ciphertext and to decipher it back to plaintext it needs Key.

CryptE1.gif

Symmetric Key Encryption

Symmetric key encryption uses same key, called secret key, for both encryption and decryption. Users exchanging data keep this key to themselves. Message encrypted with a secret key can be decrypted only with the same secret key.

The algorithm used for symmetric key encryption is called secret-key algorithm. Since secret-key algorithms are mostly used for encrypting the content of the message they are also called content-encryption algorithms.

The major vulnerability of secret-key algorithm is the need for sharing the secret-key. One way of solving this is by deriving the same secret key at both ends from a user supplied text string (password) and the algorithm used for this is called password-based encryption algorithm. Another solution is to securely send the secret-key from one end to other end. This is done using another class of encryption called asymmetric algorithm, which is discussed later.

Strength of the symmetric key encryption depends on the size of the key used. For the same algorithm, encrypting using longer key is tougher to break than the one done using smaller key. Strength of the key is not liner with the length of the key but doubles with each additional bit.

Following are some of popular secret-key algorithms and the key size that they use
RC2 - 64 bits
DES 64 bits
3DES 192 bits
AES 256 bits
IDEA 128 bits
CAST 128 bits (CAST256 uses 256 bits key)
Algorithm Parameters:

  1. Encryption Mode

    There are two types of secret-key ciphers, block ciphers and stream ciphers
    Block Ciphers convert fixed-length block of plain text into cipher text of the same length. Most of the block ciphers use a block size of 64 bits. When the message size is more than that of the block size, then the message is broken into multiple blocks and each block is encrypted separately. There are different modes in which a Block cipher can encrypt these blocks. Viz., Cipher Block Chaining (CBC), Electronic Codebook (ECB) or Cipher Feedback (CFB). Of these CBC mode is more commonly used. In CBC Mode, each plain text block is XORed with the previous cipher text block before being encrypted. Some famous Block ciphers are DES, 3DES, IDEA, SAFER, Blowfish and Skipjack (used by US National Security Agency).
    Stream Ciphers operate on small group of bits, typically applying bitwise XOR operations to them using the key as a sequence of bits. Some famous stream ciphers include RC4 and SEAL.

  2. Initialization Vector

    Since Block ciphers working on CBC modes XOR each block with the previous encrypted block, the first block of the message needs a byte array, of same block size, with which it will be XORed This byte array is called IV or Initialization Vector.
    Following are some block ciphers with their normal block size
    DES - 64 bits
    3DES 64 bits
    AES 128 bits

  3. Padding

    Often last block of the message will be smaller that the expected block size in which case a predetermined string will be repeatedly added to the end of the block to make it to the expected size. For instance if the block size is 64 bits and the last block has only 40 bits then 24 bits of padding will be added to it. There were two ways to add the pad, either by adding zeros or the number of the bytes that needs to be added (in this case it will be 3).

Asymmetric Key Encryption

Asymmetric key encryption uses different keys for encryption and decryption. These two keys are mathematically related and they form a key pair. One of these two keys should be kept private, called private-key, and the other can be made public (it can even be sent in mail), called public-key. Hence this is also called Public Key Encryption.

A private key is typically used for encrypting the message-digest; in such an application private-key algorithm is called message-digest encryption algorithm. A public key is typically used for encrypting the secret-key; in such a application private-key algorithm is called key encryption algorithm.

Popular private-key algorithms are RSA (invented by Rivest, Shamir and Adlemen) and DSA (Digital Signature Algorithm). While for an ordinary use of RSA, a key size of 768 can be used, but for corporate use a key size of 1024 and for extremely valuable information a key size of 2048 should be used.

Asymmetric key encryption is much slower than symmetric key encryption and hence they are only used for key exchanges and digital signatures.

To learn more about cryptography refer RAS Security site. http://www.rsasecurity.com/rsalabs/faq/3.html

Cryptography in Microsoft .NET

Microsoft.NET has classes that extend the cryptographic services provided by Windows CryptoAPI.

System.Security.Cryptography namespace of Common Language runtime provides classes for 

  1. Symmetric Key Encryption
  2. Asymmetric Key Encryption
  3. Hashing 
  4. Digital Certificates
  5. XML Signatures

Symmetric Key Encryption and Asymmetric Key Encryption are discussed in this article. Hashing, Digital Certificates and XML Signatures will be discussed is the subsequent articles.

Symmetric Key Encryption in .NET:

Symmetric Algorithms are implemented using a three level inheritance pattern.
The root level abstract class, SymmetricAlgorithm (System.Security.Cryptography.SymmetricAlgorithm), specifies that it is a Symmetric algorithm. Intermediate classes are named after particular type of symmetric algorithm that they implement and are also abstract. The final level class provides the complete implementation of the Symmetric Algorithms by either using the Cryptographic Service Providers of the windows CryptoAPI or by completely implementing the algorithm in .NET. While the former classes has CryptoServiceProvider suffix the later has Managed suffix.

CryptE2.gif

When the concrete class (RC2CryptoServiceProvider, DESCryptoService Provider, TrippleDESCryptoService Provider and RijndaelManaged) is instantiated, the default constructor generates a strong secret-key, initializes the IV, sets sensible values for padding and mode.

RijndaelManaged rj = new RijndaelManaged();
Console.WriteLine("AES Mode is : " + rj.Mode);
Console.WriteLine("AES Padding is : " + rj.Padding );
Console.WriteLine("AES Key Size : " + rj.KeySize);

This will generate an output as below
AES Mode is : CBC
AES Padding is : PKCS7
AES Key Size : 256

Asymmetric Key Encryption in .NET:

Similar to Symmetric key algorithms asymmetric is also implemented using a three level inheritance pattern.

When the concrete class ( RSACryptoServiceProvider or DSACryptoService Provider) is instantiated, the default constructor always generate a random key pair ( strong key values). Also the asymmetric algorithms can be made to retrieve the existing key pair from the key container of CSP.

CryptE3.gif

// Create the CspParameters object
CspParameters cp = new CspParameters();
// Set the key container name that has the RSA key pair
cp.KeyContainerName = "ApplicationKeyContainer";
// Create the RSA CSP passing CspParameters object
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cp);
Console.WriteLine("RSA Key Size :" + rsa.KeySize);
Console.WriteLine("RSA Key is : \n" + rsa.ToXmlString(
true));

This will generate an output as below (edited for brevity)

RSA Key Size :1024
RSA Key is :

<RSAKeyValue>
<
Modulus>t9Kue9bSrE=</Modulus>
<
Exponent>AQAB</Exponent>
<
P>7AL5vyAbw==</P>
<
Q>x2QxA23w==</Q>
<
DP>bLO+qHw==</DP>
<
DQ>h6S52sQ==</DQ>
<
InverseQ>vftt4iig==</InverseQ>
<
D>YBSd0=</D>
</
RSAKeyValue>

CspParameters has the parameters for identifying a specific Cryptographic Service Provider and a specific key container for keys.

System.Security.Cryptography.CspParameters csp = new CspParameters();
// Set the key container name that has the RSA key pair
csp.KeyContainerName = "TestMe2";
//Set the CSP Provider Type PROV_RSA_FULL
csp.ProviderType = 1;
//Set the CSP Provider Name
csp.ProviderName = "Microsoft Base Cryptographic Provider v1.0";
//Create a DSA cypher and intialaise it with the CspParameters
RSACryptoServiceProvider _cipher = new RSACryptoServiceProvider(csp);
Console.WriteLine("Cipher :" + _cipher.ToString());
Console.WriteLine("Key : " + _cipher.ToXmlString(
true));
Console.WriteLine("Key Size : " + _cipher.KeySize);
Console.WriteLine("KeyExchangeAlgorithm : " + _cipher.KeyExchangeAlgorithm );
Console.WriteLine("SignatureAlgorithm : " + _cipher.SignatureAlgorithm );

This will generate an output as below

Cipher :System.Security.Cryptography.RSACryptoServiceProvider
Key :

<RSAKeyValue><Modulus>2FccOXusxV+lstX8frCDvw1z6gpl1VDDnwzoLDVHJ3zWjtyKqc2lObTGDu2a
JHXcTU7RvGodTH1Xdh/woJJbeCYDtEk5zMfF1FOjugEhOnWaCkQm73d4Tr33e4ofn/rlqh983rSJlpSu5L0
CAJKtDZ+WaHQhLsFqtOPQUQL4qH0=
</Modulus><Exponent>AQAB</Exponent>
<
P>+Sft+l8T0IuaOQL6zMujcJklopLK9pMGeGWyMXJvPqDQwOXh2tBkhuQTSqP7QH8yJ7
AZ03trqZ/h0rFuSSy20Q==
</P><Q>3khrfySCAEVHVTTvgXNXvQu1M/xaEuwhxw57j4VXJVANwZ
TCdNtQwprgmoB5q0jLLRRZP/pNCA1LqOy8+2kZ7Q==
</Q><DP>+Hm3vS9AhYQTo7OzBrY3Ir24a
K9YNhteIofY87MZ+i1KwnT/jsaw2k1uZ8utcB7pl+bpepzlO960yPgl8lfjYQ==
</DP><DQ>x4OpOQ3D
wgps5IYHE+I7tmtz0Z2IG8Pm7YyKS2AbwFoCfubPQ6Q28PWi9AqtKpjEBUpmcY5w5fFJH+6eEetc
YQ==
</DQ><InverseQ>5IvEUcDA7UIhx0FU9nY8ZnC/P+GaT/54mR2xe9Hlp1XQsOtToFn1Dzd9Evx
FcTqO6hGntRAPLqNBFle3i5xvRA==
</InverseQ><D>j9ib87zADByk2FxgHvzPHOGdCSkQvN2Ot
NqoJXznauIe567MpEsQaWZBqvthWozjhqO54UXNZWaSGQDzxlCKcAefAurJhZJ/HE0Yemm+
9cSqynZcT0UAPRAxzi7KSGuPKTOkn58hyQNtRP7DWHAILuUQ5c75Mu8UXkxxy5bjsgE=
</D>
</
RSAKeyValue>

Key Size : 1024
KeyExchangeAlgorithm : RSA-PKCS1-KeyEx
SignatureAlgorithm : http://www.w3.org/2000/09/xmldsig#rsa-sha1

Windows 2000 Professional comes with the following CSP

CryptE4.gif

For more details on CSP Provider Types refer http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/Security/cryptographic_provider_types.asp

Stream based Programming:

Cryptographic namespaces uses the same Stream (System.IO.Stream) oriented design that permeates the .NET framework from networking (System.Net) to XML (System.XML). A new class called CryptoStream (System.Security.Cryptography.CryptoStream) derived from System.IO.Stream is used for both encryption and decryption of data.

Following snippet shows how to encrypt a string using RijndaelManaged (For full example refer TextEncrpytion Class)

//Create a memory stream to which CryptoStream
//will write the cipher text
MemoryStream ciphertextmem = new MemoryStream();
//Create a CryptoStream in Write Mode; initialise with the
//Rijndael's Encryptor ICryptoTransform
CryptoStream crystm = new CryptoStream(ciphertextmem,
_rj.CreateEncryptor(),CryptoStreamMode.Write);
//Encode the passed plain text string into Unicode byte stream
Byte[] plaintextbyte = new UnicodeEncoding().GetBytes(plaintext);
//Write the plaintext byte stream to CryptoStream
crystm.Write(plaintextbyte,0,plaintextbyte.Length);
//don't forget to close the stream
crystm.Close();
//Extract the ciphertext byte stream and close the MemoryStream
Byte[] ciphertextbyte = ciphertextmem.ToArray();
ciphertextmem.Close();
//Encode the ciphertext byte into Unicode string
string ciphertext = new UnicodeEncoding().GetString(ciphertextbyte);
Following snippet shows how to decrypt a
string using RijndaelManaged
//Create a memory stream from which CryptoStream will read the
//cipher text
MemoryStream ciphertextmem = new MemoryStream(new UnicodeEncoding().GetBytes(ciphertext));
//Create a CryptoStream in Read Mode; initialise withe the
//Rijndael's Decryptor ICryptoTransform
CryptoStream crystm = new CryptoStream(ciphertextmem,_rj.CreateDecryptor(),CryptoStreamMode.Read);
//Create a temporary memory stream to which we will copy the
//plaintext byte array from CryptoStream
MemoryStream plaintextmem = new MemoryStream();
do
{
//Create a byte array into which we will read the plaintext
//from CryptoStream
Byte[] buf = new Byte[100];
//read the plaintext from CryptoStream
int actualbytesread = crystm.Read(buf,0,100);
//if we have reached the end of stream quit the loop
if (0 == actualbytesread)
break;
//copy the plaintext byte array to MemoryStream
plaintextmem.Write(buf,0,actualbytesread);
}
while(true);
//don't forget to close the streams
crystm.Close();
ciphertextmem.Close();
//Extract the plaintext byte stream and close the MemoryStream
Byte[] plaintextbyte = plaintextmem.ToArray();
plaintextmem.Close();
//Encode the plaintext byte into Unicode string
string plaintext = new UnicodeEncoding().GetString(plaintextbyte);

Configuring Cryptography

Cryptographic namespaces uses the ubiquitous XML based configuration for the algorithms. cryptoNameMapping provides friendly names for the ciphers ( algorithms), these friendly names can be used from the Create static methods of the abstract classes (System.Secyrity.Cryptography.AsymmetricAlgorithm, System.Secyrity.Cryptography.SymmetricAlgorithm) for creating a specific cipher class

For instance the following configuration file shows two custom symmetric ciphers, MyCryptoClass1 and MyCryptoClass2 implemented in MyAssembly assembly.

<cryptographySettings>
<
cryptoNameMapping>
<
cryptoClasses>
<
cryptoClass MyCrypto1="MyCryptoClass, MyAssembly Culture='en', PublicKeyToken=a5d015c7d5a0b012, Version=1.0.0.0"/>
<
cryptoClass MyCrypto2="MyCryptoClass2, MyAssembly Culture='en', PublicKeyToken=a5d015c7d5a0b012, Version=1.0.0.0"/>
</
cryptoClasses>
<
nameEntry name="System.Security.Cryptography. SymmetricAlgorithm" class=" MyCrypto1"/>
</
cryptoNameMapping>
</
cryptographySettings>

Of these two classes MyCryptoClass1 is set as the default class for SymmetricAlgorithm

//Creates the default implementation, which is MyCrypto1.
SymmetricAlgorithm _cipher = SymmetricAlgorithm.Create();
//Creates the MyCrypto2 implementation.
SymmetricAlgorithm _cipher = SymmetricAlgorithm.Create( MyCrypto2);

By default without any configuration changes, the default implementation created for SymmetricAlgorithm is RijndaelManaged and for AsymmetricAlgorithm is RSACryptoServiceProvider

CryptographySettings should be inside the <mscorlib> as

<configuration>
<
mscorlib>
<
cryptographySettings>
..
..
</cryptographySettings>
</
mscorlib>
</
configuration>

CryptoConfig class (System.Security.Cryptography.CryptoConfig) is the helper class for accessing Cryptography Settings.

AsymmetricAlgorithm _cipher = (AsymmetricAlgorithm) CryptoConfig.CreateFromName("System.Security.Cryptography.DSA");
Console.WriteLine("Cipher :" + _cipher.ToString());
Console.WriteLine("Key : " + _cipher.ToXmlString(
true));
Console.WriteLine("Key Size : " + _cipher.KeySize);
Console.WriteLine("KeyExchangeAlgorithm : " + _cipher.KeyExchangeAlgorithm );
Console.WriteLine("SignatureAlgorithm : " + _cipher.SignatureAlgorithm );

This will generate an output as below (edited for brevity)
Cipher : System.Security.Cryptography.DSACryptoServiceProvider
Key :
<DSAKeyValue><P>uZPdyk=</P><Q>+gxcEM=</Q><G>O+
R9ws=
</G><Y>k=</Y><J>w24</J><Seed>TA8=</Seed><PgenCounter>AeA=
</PgenCounter><X>9M..5Bpc=</X></DSAKeyValue>

Key Size : 1024
KeyExchangeAlgorithm :
SignatureAlgorithm:
http://www.w3.org/2000/09/xmldsig#dsa-sha1

DSA does not supports key-encryption algorithm (KeyExchnage Algorithm) and hence the output has nothing for KeyExchangeAlgorithm :. Whereas it supports DSS, hence it has http://www.w3.org/2000/09/xmldsig#dsa-sha1 for SignatureAlgorithm

Next Article

This article intentionally ignored the Signature and hashing related function of Encryption classes as they are dealt in the subsequent articles.

The subsequent articles deals with Hashing, Signatures, Certificates, XML- Signature and XML- Encryption They also delves into the details of using Digital Signatures, Digital Envelopes, Digital Certificates in Microsoft.Net.


Similar Articles